/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * tameshi
 * Copyright (C) Massimiliano Maniscalco 2012 <massi.neptune@yahoo.com>
 * 
tameshi is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * tameshi is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "controller.h"
#include "parser_xml.h"
#include "test_sceltamult_domande.h"

void Controller::
load_data ( const Glib::ustring &filename )
{
	Glib::RefPtr<Gio::File> dataFile = Gio::File::create_for_path ( filename );
	if ( dataFile->query_exists () )
	{
		bool result;
		_mainStatusbar->push ( "Caricamento dati...", _stsbarItemDiskId );
		result = load_items_from_xml_file ( filename );
		if ( !result )
			_mainStatusbar->push ( Glib::ustring ( "Errore di caricamento dei dati!" ), _stsbarItemDiskId );
	}
}

bool Controller::
save_data ( const Glib::ustring &filename )
{
	char _message[32];
	Glib::ustring _messaggio ( "Salvato: " );
	int nd = 0;
	bool result = true;
	ofstream outfile ( filename.c_str(), ios_base::out );
	if ( !outfile )
	{
		cerr << "saveData:: unable to open file \"" << filename << "\"" << endl;
		result = false;
	}
	else
	{
		outfile << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
		outfile << "<tameshi>\n";
		nd = save_items_to_xml_file ( *_domande, &outfile );
		if ( nd != _domande->size() )
			result = false;
		else
		{
			_shouldSaveDomande = false;
			if ( nd == 1 )
				sprintf( _message, "( %d domanda ) ", nd );
			else
				sprintf( _message, "( %d domande ) ", nd );
			_messaggio += Glib::ustring ( _message );
		}
		outfile << "</tameshi>";
		if ( outfile.fail() )
			result = false;
		outfile.close();
	}
	_mainStatusbar->pop ( _stsbarItemDiskId );
	if ( result )
		_mainStatusbar->push ( _messaggio, _stsbarItemDiskId );
	else
		_mainStatusbar->push ( Glib::ustring ( "Errore di salvataggio dei dati!" ), _stsbarItemDiskId );
	return result;
}

bool Controller::
load_items_from_xml_file ( const Glib::ustring &filename )
{
	bool result = false;
	if ( filename != Glib::ustring ( "" ) )
	{
		sigc::connection _parserXmlDomandaImported;
		sigc::connection _parserXmlImportEnd;
		// Parse the entire document in one go:
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		try
		{
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED 
			ParserXML parser;
			parser.set_substitute_entities(true); //
			_domandeCaricate = 0;
			result = true;
			_parserXmlDomandaImported = parser.signal_domanda_imported ().connect (sigc::mem_fun (this, &Controller::on_signal_domanda_loaded) );
			_parserXmlImportEnd = parser.signal_import_end ().connect (sigc::mem_fun (this, &Controller::on_signal_import_end) );
			parser.parse_file(filename);
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		}
		catch(const xmlpp::exception& ex)
		{
			std::cout << "libxml++ exception: " << ex.what() << std::endl;
			result = false;
		}
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
		_parserXmlDomandaImported.disconnect();
		_parserXmlImportEnd.disconnect ();
	}
	return result;
}

template <class ItemClass>
int Controller::
save_items_to_xml_file ( list<ItemClass> &_itemsList, ofstream *xmlstr )
{
	int ni = -1;
	if ( !*xmlstr )
		cerr << "saveItemsToXmlFile:: unable to open file!" << endl;
	else
	{
		ni++;
		class list<ItemClass>::iterator _qit = _itemsList.begin();
		class list<ItemClass>::iterator _qend = _itemsList.end();
		while ( _qit != _qend )
		{
			*xmlstr << _qit->get_domanda_xml ().raw();
			if ( xmlstr->fail() )
			{
				cerr << "saveItemsToXmlFile:: file writing error!"<< endl;
				break;
			}
			_qit++;
			ni++;
		}
	}
	return ni;
}

void Controller::
connect_signals ( void )
{
	// main win
	_mainWin->signal_focus_in_event ().connect (sigc::mem_fun (this, &Controller::on_main_win_focus_in) );
	_mainWin->signal_focus_out_event ().connect (sigc::mem_fun (this, &Controller::on_main_win_focus_out) );
	// main toolbar
	_saveToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_save_action_clicked) );
	_importToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_import_action_clicked) );
	_addToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_add_action_clicked) );
	_remToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_remove_action_clicked) );
	_editToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_edit_action_clicked) );
	_infoToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_info_action_clicked) );
	_resetToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_reset_action_clicked) );
	_duplicatiToolButton->signal_toggled ().connect (sigc::bind<Gtk::Widget*>(sigc::mem_fun (this, &Controller::on_search_duplicati_action_clicked), _duplicatiToolButton) );
	_searchToolButton->signal_toggled ().connect (sigc::mem_fun (this, &Controller::on_search_action_clicked) );
	_testToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_test_action_clicked) );
	_quickSearchEntry->signal_icon_press ().connect (sigc::mem_fun (this, &Controller::on_quick_search_icon_clicked) );
	_quickSearchEntry->get_buffer ()->signal_inserted_text ().connect (sigc::mem_fun (this, &Controller::on_quick_search_text_inserted) );
	_quickSearchEntry->get_buffer ()->signal_deleted_text ().connect (sigc::mem_fun (this, &Controller::on_quick_search_text_deleted) );
	// quick search menu
	_quickSearchAllMenuItem->signal_toggled ().connect (sigc::bind<Gtk::RadioMenuItem*>(sigc::mem_fun (this, &Controller::on_quick_search_menu_toggled), _quickSearchAllMenuItem) );
	_quickSearchCodiceMenuItem->signal_toggled ().connect (sigc::bind<Gtk::RadioMenuItem*>(sigc::mem_fun (this, &Controller::on_quick_search_menu_toggled), _quickSearchCodiceMenuItem) );
	_quickSearchDomandaMenuItem->signal_toggled ().connect (sigc::bind<Gtk::RadioMenuItem*>(sigc::mem_fun (this, &Controller::on_quick_search_menu_toggled), _quickSearchDomandaMenuItem) );
	_quickSearchArgomentoMenuItem->signal_toggled ().connect (sigc::bind<Gtk::RadioMenuItem*>(sigc::mem_fun (this, &Controller::on_quick_search_menu_toggled), _quickSearchArgomentoMenuItem) );
	// main menu
	_saveMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_save_action_clicked) );
	_importMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_import_action_clicked) );
	_quitMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_quit_menu_selected) );
	_newMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_add_action_clicked) );
	_remMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_remove_action_clicked) );
	_editMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_edit_action_clicked) );
	_resetMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_reset_action_clicked) );
	_infoMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_info_action_clicked) );
	_duplicatiMenuitem->signal_toggled ().connect (sigc::bind<Gtk::Widget*>(sigc::mem_fun (this, &Controller::on_search_duplicati_action_clicked), _duplicatiMenuitem) );
	_aboutMenuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_about_action_clicked) );
	// domande tree view
	_domandeListView->signal_button_press_event ().connect_notify (sigc::mem_fun (this, &Controller::on_domande_tree_double_clicked) );
	_domandeListSelection->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_items_tree_selection_changed) );
	// import
	_importButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::import_select_file) );
	// edit window
	_editBoldToolButton->signal_clicked ().connect (sigc::bind<Glib::ustring>( sigc::mem_fun (this, &Controller::on_edit_tag_apply), Glib::ustring ( "bold" ) ) );
	_editUnderlineToolButton->signal_clicked ().connect (sigc::bind<Glib::ustring>( sigc::mem_fun (this, &Controller::on_edit_tag_apply), Glib::ustring ( "underline" ) ) );
	_editSuperscriptToolButton->signal_clicked ().connect (sigc::bind<Glib::ustring>( sigc::mem_fun (this, &Controller::on_edit_tag_apply), Glib::ustring ( "superscript" ) ) );
	_editHighlightToolButton->signal_clicked ().connect (sigc::bind<Glib::ustring>( sigc::mem_fun (this, &Controller::on_edit_tag_apply), Glib::ustring ( "highlight" ) ) );
	_editEraseToolButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_edit_erase_tag) );
	_editConfermaButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_edit_conferma_button_clicked) );
	_editAnnullaButton->signal_clicked ().connect ( sigc::bind<Gtk::Window*>( sigc::mem_fun (this, &Controller::on_cancel_button_clicked), _editWin ) );
	// info window
	infoPreviousButton->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_previous_info_item_action) );
	infoNextButton->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_next_info_item_action) );
	// search window
	_searchConfermaButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_search_conferma_button_clicked) );
	_searchDefaultButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_search_default_button_clicked) );
	// test options window
	_testOptIniziaButton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_test_opt_inizia_button_clicked) );
	_testOptAnnullaButton->signal_clicked ().connect ( sigc::bind<Gtk::Window*>( sigc::mem_fun (this, &Controller::on_cancel_button_clicked), _testOptWin ) );
}

void Controller::
on_cancel_button_clicked ( Gtk::Window *win )
{
	win->hide ();
}

bool Controller::
on_main_win_focus_in ( GdkEventFocus *event )
{
	if ( _startingApp == STATUS_STARTING )
	{
		Glib::Threads::Thread *loader = Glib::Threads::Thread::create (sigc::bind<Glib::ustring&>(sigc::mem_fun (this, &Controller::load_data), _dataPath ) );
		_startingApp = STATUS_LOADING;
	}
	_mainMenuBar->set_sensitive ( true );
	_mainToolbar->set_sensitive ( true );
	_domandeListView->set_sensitive ( true );
	return false;
}

bool Controller::
on_main_win_focus_out ( GdkEventFocus *event )
{
	_mainMenuBar->set_sensitive ( false );
	_mainToolbar->set_sensitive ( false );
	_domandeListView->set_sensitive ( false );
	return false;
}

void Controller::
on_items_tree_selection_changed ( void )
{
	Glib::ustring _messaggio;
	int _nr = _domandeListSelection->count_selected_rows ();
	if ( _nr == 0 )
		_messaggio.append ( Glib::ustring::compose( "Nessuna domanda selezionata di %1.", Glib::ustring::format( _domande->size() ) ) );
	if ( _nr == 1 )
		_messaggio.append ( Glib::ustring::compose( "Una domanda selezionata di %1.", Glib::ustring::format( _domande->size() ) ) );
	if ( _nr > 1 )
		_messaggio.append ( Glib::ustring::compose( "%1 domande selezionate di %2.", Glib::ustring::format( _nr ), Glib::ustring::format( _domande->size() ) ) );
	_mainStatusbar->pop ( _stsbarItemSelId );
	_mainStatusbar->push ( _messaggio, _stsbarItemSelId );
	if ( _nr > 0 )
	{
		if ( !_remToolButton->get_sensitive () )
		{
			_remToolButton->set_sensitive ( true );
			_remMenuitem->set_sensitive ( true );
		}
		if ( !_editToolButton->get_sensitive () )
		{
			_editToolButton->set_sensitive ( true );
			_editMenuitem->set_sensitive ( true );
		}
		if ( !_infoToolButton->get_sensitive () )
		{
			_infoToolButton->set_sensitive ( true );
			_infoMenuitem->set_sensitive ( true );
		}
		if ( !_resetToolButton->get_sensitive () )
		{
			_resetToolButton->set_sensitive ( true );
			_resetMenuitem->set_sensitive ( true );
		}
		if ( !_duplicatiToolButton->get_sensitive () )
		{
			_duplicatiToolButton->set_sensitive ( true );
			_duplicatiMenuitem->set_sensitive ( true );
		}
	}
	else
	{
		if ( _remToolButton->get_sensitive () )
		{
			_remToolButton->set_sensitive ( false );
			_remMenuitem->set_sensitive ( false );
		}
		if ( _editToolButton->get_sensitive () )
		{
			_editToolButton->set_sensitive ( false );
			_editMenuitem->set_sensitive ( false );
		}
		if ( _infoToolButton->get_sensitive () )
		{
			_infoToolButton->set_sensitive ( false );
			_infoMenuitem->set_sensitive ( false );
		}
		if ( _resetToolButton->get_sensitive () )
		{
			_resetToolButton->set_sensitive ( false );
			_resetMenuitem->set_sensitive ( false );
		}
		if ( !_duplicatiToolButton->get_active () && _duplicatiToolButton->get_sensitive () )
		{
			_duplicatiToolButton->set_sensitive ( false );
			_duplicatiMenuitem->set_sensitive ( false );
		}
	}
}

void Controller::
get_tree_row_ref ( const vector<Gtk::TreePath> &_sel, Glib::RefPtr<Gtk::TreeModel> _listModel, vector<Gtk::TreeRowReference> &_selRef )
{
	vector<Gtk::TreePath>::const_iterator _iter = _sel.begin();
	vector<Gtk::TreePath>::const_iterator _end = _sel.end();
	while ( _iter != _end )
	{
		Gtk::TreeRowReference _ref = Gtk::TreeRowReference ( _listModel, *_iter );
		_selRef.push_back ( _ref );
		_iter++;
	}
}

list<Domanda>::iterator Controller::
get_domanda_iterator ( Gtk::TreeModel::Row _row )
{
	list<Domanda>::iterator _it;
	Domanda _temp;
	_temp.set_codice ( _row[_domandeListColumns->codice] );
	_it = find (_domande->begin(), _domande->end(), _temp);
	return _it;
}

void Controller::
load_pop_up_button ( vector<Glib::ustring>::iterator _start, vector<Glib::ustring>::iterator _end, Glib::RefPtr<Gtk::ListStore> _popUpList )
{
	while ( _start != _end )
	{
		Gtk::TreeModel::iterator iter = _popUpList->append();
		Gtk::TreeModel::Row row = *iter;
		row[_buttonPopUpColumn->columnCell] = *_start;
		_start++;
	}
}

void Controller::
on_save_action_clicked ( void )
{
	if ( save_data( _dataPath ) )
	{
		_saveToolButton->set_sensitive ( false );
		_saveMenuitem->set_sensitive ( false );
	}
}

void Controller::
on_import_action_clicked ( void )
{
	_importWin->present ();
}

void Controller::
on_quit_menu_selected ( void )
{
	_mainApp->quit ();
}

void Controller::
on_add_action_clicked ( void )
{
	_editCodiceEntry->set_text ( "" );
	_editDomandaTxtBfr->set_text ( "" );
	_editRispATxtBfr->set_text ( "" );
	_editRispBTxtBfr->set_text ( "" );
	_editRispCTxtBfr->set_text ( "" );
	_editRispDTxtBfr->set_text ( "" );
	_editCorrettaCombobox->set_active ( 0 );
	_editWin->present ();
}

void Controller::
on_remove_action_clicked ( void )
{
	Gtk::MessageDialog *_alertDialog = new Gtk::MessageDialog ( *_mainWin, "Vuoi eliminare definitivamente le domande selezionate?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
	int res_id = _alertDialog->run();
	delete _alertDialog;
	if ( res_id == Gtk::RESPONSE_YES )
	{
		vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ();
		domande_tree_remove_selected_rows ( _selected );
		_shouldSaveDomande = true;
		_saveToolButton->set_sensitive ( true );
		_saveMenuitem->set_sensitive ( true );
	}
}

void Controller::
on_edit_action_clicked ( void )
{
	vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ();
	int nrSel = _domandeListSelection->count_selected_rows ();
	Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
	if ( nrSel > 0 )
	{
		vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
		Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
		list<Domanda>::iterator _it = get_domanda_iterator ( *_iterView );
		if ( _it != _domande->end() )
		{
			populate_edit_window ( *_it );
			_editWin->present ();
		}
	}
}

void Controller::
on_info_action_clicked ( void )
{
	vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ();
	int nrSel = _domandeListSelection->count_selected_rows ();
	Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
	if ( nrSel > 0 )
	{
		vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
		Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
		Gtk::TreeModel::iterator _iterBegin = _domandeListStore->children().begin();
		if ( _iterView != _iterBegin )
			infoPreviousButton->set_sensitive ( true );
		else
			infoPreviousButton->set_sensitive ( false );
		Gtk::TreeModel::iterator _iterEnd = _domandeListStore->children().end();
		_iterEnd--;
		if ( _iterView != _iterEnd )
			infoNextButton->set_sensitive ( true );
		else
			infoNextButton->set_sensitive ( false );
		list<Domanda>::iterator _it = get_domanda_iterator ( *_iterView );
		if ( _it != _domande->end() )
		{
			if ( nrSel > 1 )
				_infoWin->set_title ( " --- Selezione multipla ---" );
			else
			{
				int ore, minuti, secondi;
				_infoWin->set_title ( "Informazioni su " + _it->get_codice() );
				_infoRisposteEntry->set_text ( Glib::ustring::format ( _it->get_risposte() ) );
				_infoCorretteEntry->set_text ( Glib::ustring::format ( _it->get_corrette() ) );
				if ( _it->get_risposte () > 0 )
				{
					_infoProbabilitaEntry->set_text ( Glib::ustring::compose ( "%1%%", Glib::ustring::format ( ( _it->get_corrette () * 100 ) / _it->get_risposte() ) ) );
					if ( _it->get_ultima () )
						_infoUltimaLabel->set_text ( "L'ultima volta hai risposto correttamente" );
					else
						_infoUltimaLabel->set_text ( "L'ultima volta non hai risposto correttamente" );
					int tempoMedio = _it->get_tempo_totale () / _it->get_risposte ();
					ore = tempoMedio / 3600;
					minuti = ( tempoMedio - ( ore * 60 ) ) / 60;
					secondi = tempoMedio - ( ore * 60 ) - ( minuti * 60 );
					_infoTempoMedioEntry->set_text ( Glib::ustring::compose ( "%1:%2:%3", Glib::ustring::format ( setfill(L'0'), setw(2), ore ), Glib::ustring::format ( setfill(L'0'), setw(2), minuti ), Glib::ustring::format ( setfill(L'0'), setw(2), secondi ) ) );
				}
				else
				{
					_infoProbabilitaEntry->set_text ( "--- %" );
					_infoUltimaLabel->set_text ( "" );
					_infoTempoMedioEntry->set_text ( "---" );
				}
				ore = _it->get_tempo_totale () / 3600;
				minuti = ( _it->get_tempo_totale () - ( ore * 60 ) ) / 60;
				secondi = _it->get_tempo_totale () - ( ore * 60 ) - ( minuti * 60 );
				_infoTempoTotaleEntry->set_text ( Glib::ustring::compose ( "%1:%2:%3", Glib::ustring::format ( setfill(L'0'), setw(2), ore ), Glib::ustring::format ( setfill(L'0'), setw(2), minuti ), Glib::ustring::format ( setfill(L'0'), setw(2), secondi ) ) );
				minuti = _it->get_ultimo_tempo () / 60;
				secondi = _it->get_ultimo_tempo () - ( minuti * 60 );
				_infoUltimoTempoEntry->set_text ( Glib::ustring::compose ( "%1:%2", Glib::ustring::format ( setfill(L'0'), setw(2), minuti ), Glib::ustring::format ( setfill(L'0'), setw(2), secondi ) ) );
			}
		}
		_infoWin->present ();
	}
}

void Controller::
on_reset_action_clicked ( void )
{
	Gtk::MessageDialog *_alertDialog = new Gtk::MessageDialog ( *_mainWin, "Vuoi azzerare definitivamente le statistiche delle domande selezionate?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
	int res_id = _alertDialog->run();
	delete _alertDialog;
	if ( res_id == Gtk::RESPONSE_YES )
	{
		vector<Gtk::TreeRowReference> _selRef;
		Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
		get_tree_row_ref ( _domandeListSelection->get_selected_rows (), _domandeListModel, _selRef );
		vector<Gtk::TreeRowReference>::iterator _srIter = _selRef.begin();
		vector<Gtk::TreeRowReference>::iterator _srEnd = _selRef.end();
		while ( _srIter != _srEnd )
		{
			Gtk::TreeModel::iterator _itRem = _domandeListModel->get_iter ( _srIter->get_path () );
			list<Domanda>::iterator _it = get_domanda_iterator ( *_itRem );
			if ( _it != _domande->end() )
				_it->reset ();
			else
				cerr << "Errore: non trovo la domanda" << endl;
			_srIter++;
		}
		_shouldSaveDomande = true;
		_saveToolButton->set_sensitive ( true );
		_saveMenuitem->set_sensitive ( true );
	}
}

void Controller::
on_search_duplicati_action_clicked ( const Gtk::Widget *sender )
{
	bool attivo;
	bool esegui = true;
	if ( sender == _duplicatiToolButton )
	{
		attivo = _duplicatiToolButton->get_active ();
		if ( _duplicatiMenuitem->get_active () == attivo )
			esegui = false;
		else
			_duplicatiMenuitem->set_active ( attivo );
	}
	if ( sender == _duplicatiMenuitem )
	{
		attivo = _duplicatiMenuitem->get_active ();
		if ( _duplicatiToolButton->get_active () == attivo )
			esegui = false;
		else
			_duplicatiToolButton->set_active ( attivo );
	}
	if ( esegui )
	{
		if ( attivo )
		{
			vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ();
			int nrSel = _domandeListSelection->count_selected_rows ();
			Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
			if ( nrSel > 0 )
			{
				Glib::ustring stringa;
				vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
				Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
				list<Domanda>::iterator _domandaModello = get_domanda_iterator ( *_iterView );
				if ( _domandaModello != _domande->end() )
				{
					_domandaModello->set_is_duplicato ( true );
					set<Glib::ustring> *parole = new set<Glib::ustring>();
					Glib::ustring modello = _domandaModello->parse_domanda ( parole );
					unsigned short matchLine = ( parole->size() / 4 ) + (  parole->size() % 4 );
					list<Domanda>::iterator itQuae = _domande->begin();
					list<Domanda>::iterator endQuae = _domande->end();
					while ( itQuae != endQuae )
					{
						if ( _domandaModello->get_codice () != itQuae->get_codice () )
						{
							set<Glib::ustring> *words = new set<Glib::ustring>();
							unsigned short wrdmatch;
							Glib::ustring frase = itQuae->parse_domanda ( words );
							if ( modello == frase )
								itQuae->set_is_duplicato ( true );
							else
							{
								wrdmatch = compare_words_set ( parole, words );
								if ( wrdmatch >= matchLine )
									itQuae->set_is_duplicato ( true );
								else
								{
									if ( itQuae->get_is_duplicato () )
										itQuae->set_is_duplicato ( false );
								}
							}
							delete words;
						}
						itQuae++;
					}
					delete parole;
				}
				load_domande_in_tree_view ();
			}
		}
		else
		{
			if ( _domandeListSelection->count_selected_rows () == 0 )
			{
				_duplicatiToolButton->set_sensitive ( false );
				_duplicatiMenuitem->set_sensitive ( false );
			}
			load_domande_in_tree_view ();
		}
	}
}

void Controller::
on_search_action_clicked ( void )
{
	_searchWin->present ();
}

void Controller::
on_test_action_clicked ( void )
{
	_testOptWin->present ();
}

void Controller::
on_quick_search_icon_clicked ( Gtk::EntryIconPosition icon_position, const GdkEventButton* event)
{
	_quickSearchMenu->popup ( 0, gtk_get_current_event_time () );
}

void Controller::
on_quick_search_text_inserted ( guint position, const gchar* chars, guint n_chars )
{
	load_domande_in_tree_view ();
}

void Controller::
on_quick_search_text_deleted ( guint position, guint n_chars )
{
	load_domande_in_tree_view ();
}

void Controller::
on_quick_search_menu_toggled ( Gtk::RadioMenuItem *sender )
{
	if ( sender->get_active () )
		load_domande_in_tree_view ();
}

void Controller::
on_about_action_clicked ( void )
{
	Gtk::AboutDialog *_about;
	Glib::RefPtr<Gdk::Pixbuf> _logo = _mainWin->get_icon ();
	_about = new Gtk::AboutDialog ();
	_about->set_program_name ( Glib::ustring ( "Tameshi" ) );
	_about->set_version ( Glib::ustring ( "0.2 beta (030b)" ) );
	_about->set_copyright ( Glib::ustring ( "Copyright © Massimiliano Maniscalco 2012" ) );
	_about->set_license ( Glib::ustring ( "Tameshi is free software: you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by the\nFree Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nTameshi is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along\nwith this program.  If not, see <http://www.gnu.org/licenses/>." ) );
	_about->set_logo ( _logo );
	_about->signal_response ().connect (sigc::bind<Gtk::AboutDialog*>( sigc::mem_fun (this, &Controller::on_about_response), _about ) );
	_about->run ();
}

void Controller::
on_about_response ( int response_id, Gtk::AboutDialog *_about )
{
	_about->hide ();
	delete _about;
}

void Controller::
load_domande_in_tree_view ( void )
{
	_domandeListStore->clear();
	Glib::ustring codStr = _searchCodiceEntry->get_text ();
	bool searchCod = (codStr != "");
	Glib::ustring domStr = _searchDomandaEntry->get_text ();
	bool searchDom = (domStr != "");
	Glib::ustring argStr = _searchArgomentoEntry->get_text ();
	bool searchArg = (argStr != "");
	Glib::ustring quickStr = _quickSearchEntry->get_text ();
	bool quickSearch = (quickStr != "");
	char quickSearchMode = -1;
	if ( quickStr != "" )
	{
		if ( _quickSearchAllMenuItem->get_active () )
			quickSearchMode = 0;
		if ( _quickSearchCodiceMenuItem->get_active () )
			quickSearchMode = 1;
		if ( _quickSearchDomandaMenuItem->get_active () )
			quickSearchMode = 2;
		if ( _quickSearchArgomentoMenuItem->get_active () )
			quickSearchMode = 3;
	}
	bool duplicati = _duplicatiToolButton->get_active ();
	list<Domanda>::iterator iterSet = _domande->begin();
	list<Domanda>::iterator iterSet_end = _domande->end();
	while (iterSet != iterSet_end)
	{
		bool _match = true;
		if ( searchCod )
		{
			if ( iterSet->get_codice().find( codStr ) == Glib::ustring::npos )
				_match = false;
		}
		if ( searchDom )
		{
			if ( iterSet->get_domanda().find( domStr ) == Glib::ustring::npos )
				_match = false;
		}
		if ( searchArg )
		{
			if ( iterSet->get_argomento().find( argStr ) == Glib::ustring::npos )
				_match = false;
		}
		if ( quickSearch )
		{
			switch ( quickSearchMode )
			{
				case 0:
					if ( (iterSet->get_codice().find( quickStr ) == Glib::ustring::npos) && (iterSet->get_domanda().find( quickStr ) == Glib::ustring::npos) && (iterSet->get_argomento().find( quickStr ) == Glib::ustring::npos) )
						_match = false;
					break;
				case 1:
					if ( iterSet->get_codice().find( quickStr ) == Glib::ustring::npos )
						_match = false;
					break;
				case 2:
					if ( iterSet->get_domanda().find( quickStr ) == Glib::ustring::npos )
						_match = false;
					break;
				case 3:
					if ( iterSet->get_argomento().find( quickStr ) == Glib::ustring::npos )
						_match = false;
					break;
			}
		}
		if ( duplicati )
		{
			if ( !iterSet->get_is_duplicato () )
				_match = false;
		}
		if ( _match )
		{
			Gtk::TreeModel::iterator iter = _domandeListStore->append();
			Gtk::TreeModel::Row row = *iter;
			row[_domandeListColumns->codice] = iterSet->get_codice();
			row[_domandeListColumns->domanda] = iterSet->get_domanda();
		}	
		iterSet++;
	}
}

void Controller::
domande_tree_remove_selected_rows ( const vector<Gtk::TreePath> &_sel )
{
	vector<Gtk::TreeRowReference> _selRef;
	Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
	get_tree_row_ref ( _sel, _domandeListModel, _selRef );
	vector<Gtk::TreeRowReference>::iterator _srIter = _selRef.begin();
	vector<Gtk::TreeRowReference>::iterator _srEnd = _selRef.end();
	while ( _srIter != _srEnd )
	{
		Gtk::TreeModel::iterator _itRem = _domandeListModel->get_iter ( _srIter->get_path () );
		list<Domanda>::iterator _it = get_domanda_iterator ( *_itRem );
		if ( _it != _domande->end() )
		{
			_domande->erase ( _it );
			_domandeListStore->erase ( _itRem );
		}
		else
			cerr << "Errore: non trovo la domanda" << endl;
		_srIter++;
	}
}
void Controller::
on_domande_tree_double_clicked ( GdkEventButton *event )
{
	if ( event->type == GDK_2BUTTON_PRESS )
	{
		vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ();
		int nrSel = _domandeListSelection->count_selected_rows ();
		Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
		if ( nrSel > 0 )
		{
			Glib::ustring stringa;
			vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
			Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
			list<Domanda>::iterator _it = get_domanda_iterator ( *_iterView );
			if ( _it != _domande->end() )
				populate_edit_window ( *_it );
			_editWin->present ();
		}
	}
}

unsigned short Controller::
compare_words_set ( set<Glib::ustring> *modelSet, set<Glib::ustring> *otherSet )
{
	unsigned short wordsMatching = 0;
	set<Glib::ustring>::iterator itot = otherSet->begin();
	set<Glib::ustring>::iterator itotend = otherSet->end();
	while ( itot != itotend )
	{
		wordsMatching += modelSet->count ( *itot );
		itot++;
	}
	return wordsMatching;
}

void Controller::
import_select_file ( void )
{
	_importWin->hide ();
	Glib::ustring filename;
	Gtk::FileChooserDialog fco( *_mainWin, Glib::ustring ( "Importa domande da file di testo" ), Gtk::FILE_CHOOSER_ACTION_OPEN );
	fco.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
	fco.add_button (Glib::ustring ( "Importa" ), Gtk::RESPONSE_OK);
	int result = fco.run();
	switch ( result )
	{
		case Gtk::RESPONSE_OK:
			filename = fco.get_filename();
			import_text_file ( filename, _importSepEntry->get_text() );
			load_domande_in_tree_view ();
			break;
		case Gtk::RESPONSE_CANCEL:
			break;
	}
}

void Controller::
import_text_file ( const Glib::ustring &filetxt, const Glib::ustring &separatore )
{
	ifstream infile ( filetxt.c_str(), ios::in );
	if ( !infile )
		cerr << "Errore: non sono riuscito ad aprire il file! " << filetxt.raw() << endl;
	else
	{
		string textline;
		Domanda *temp;
		Glib::ustring messaggio ( "Ho importato " );
		Glib::ustring error_log ( Glib::ustring::compose ( "> il carattere di separazione usato è (%1)\n\n", separatore ) );
		unsigned short conta = 0;
		unsigned short errori = 0;
		char posizione = 0;
		bool result;
		char initbuffer[5];
		char sep = separatore[0];
		infile.get ( initbuffer, 4 );   // discard the first 3 characters
		while ( getline ( infile, textline, '\n' ) )
		{
			if ( textline != "" )
			{
				Glib::ustring segmento = textline.substr ( 0, 7 );
				size_t sep_pos = textline.find ( separatore.raw() );
				if ( segmento.size() == 7 && textline.substr ( 0, sep_pos ) == segmento.raw() )
				{
					temp = new Domanda ();
					temp->set_codice ( segmento );
					result = true;
					error_log.append( Glib::ustring::compose ( "> importo domanda codice: (%1)\n", segmento ) );
				}
				else
				{
					error_log.append( Glib::ustring ( "\nERRORE: il seguente codice è fuori dalla norma\n" ) );
					error_log.append( Glib::ustring::compose ( "> i primi 7 caratteri sono: \"%1\"\n", segmento ) );
					error_log.append( Glib::ustring::compose ( "> fino al primo separatore c'è \"%1\"\n\n", textline.substr ( 0, sep_pos ) ) );
					errori++;
					temp = 0;
					result = false;
				}
				if ( result )
				{
					size_t next_sep_pos;
					string next = separatore.raw();
					next.append ( "a)" );
					if ( try_get_next_string (infile, temp, textline, next, &sep_pos, segmento) )
						temp->set_domanda ( segmento );
					else
					{
						error_log.append( Glib::ustring::compose ( "\nERRORE: domanda codice %1\n", temp->get_codice () ) );
						error_log.append( Glib::ustring ( "> non ho trovato il termine della domanda nella seguente riga:\n" ) );
						error_log.append( Glib::ustring::compose ( "%1\n", textline) );
						result = false;
						errori++;
					}
					if ( result )
					{
						next.assign( separatore.raw() );
						next.append( "b)" );
						if ( try_get_next_string (infile, temp, textline, next, &sep_pos, segmento) )
							temp->set_risposta ( segmento.substr ( 3 ), 0 ); // non include i primi 3 caratteri "a) "
						else
						{
							error_log.append( Glib::ustring::compose ( "\nERRORE: domanda codice %1\n", temp->get_codice () ) );
							error_log.append( Glib::ustring ( "> non ho trovato il termine della risposta A nella seguente riga:\n" ) );
							error_log.append( Glib::ustring::compose ( "%1\n", textline) );
							result = false;
							errori++;
						}
					}
					if ( result )
					{
						next.assign( separatore.raw() );
						next.append( "c)" );
						if ( try_get_next_string (infile, temp, textline, next, &sep_pos, segmento) )
							temp->set_risposta ( segmento.substr ( 3 ), 1 ); // non include i primi 3 caratteri "b) "
						else
						{
							error_log.append( Glib::ustring::compose ( "\nERRORE: domanda codice %1\n", temp->get_codice () ) );
							error_log.append( Glib::ustring ( "> non ho trovato il termine della risposta B nella seguente riga:\n" ) );
							error_log.append( Glib::ustring::compose ( "%1\n", textline) );
							result = false;
							errori++;
						}
					}
					if ( result )
					{
						next.assign( separatore.raw() );
						next.append( "d)" );
						if ( try_get_next_string (infile, temp, textline, next, &sep_pos, segmento) )
							temp->set_risposta ( segmento.substr ( 3 ), 2 ); // non include i primi 3 caratteri "c) "
						else
						{
							error_log.append( Glib::ustring::compose ( "\nERRORE: domanda codice %1\n", temp->get_codice () ) );
							error_log.append( Glib::ustring ( "> non ho trovato il termine della risposta C nella seguente riga:\n" ) );
							error_log.append( Glib::ustring::compose ( "%1\n", textline) );
							result = false;
							errori++;
						}
					}
					if ( result )
					{
						next.assign( separatore.raw() );
						if ( try_get_next_string (infile, temp, textline, next, &sep_pos, segmento) )
							temp->set_risposta ( segmento.substr ( 3 ), 3 ); // non include i primi 3 caratteri "d) "
						else
						{
							error_log.append( Glib::ustring::compose ( "\nERRORE: domanda codice %1\n", temp->get_codice () ) );
							error_log.append( Glib::ustring ( "> non ho trovato il termine della risposta D nella seguente riga:\n" ) );
							error_log.append( Glib::ustring::compose ( "%1\n", textline) );
							result = false;
							errori++;
						}
					}
					if ( result )
					{
						segmento.assign( textline.substr( sep_pos + 1 ) );
						bool valido = segmento.validate();
						if ( !valido )
							segmento.assign ( segmento.substr ( 1 ) );
						if ( segmento.raw() == textline.substr( textline.size() - 1, 1 ) )
							temp->set_corretta ( segmento );
						else
						{
							error_log.append( Glib::ustring::compose ( "\nERRORE: domanda codice %1\n", temp->get_codice () ) );
							error_log.append( Glib::ustring ( "> la risposta corretta non corrisponde con l'ultimo carattere utile della riga\n" ) );
							error_log.append( Glib::ustring::compose ( "> dopo l'ultimo separatore c'è \"%1\"\n\n", segmento ) );
							error_log.append( Glib::ustring::compose ( "> l'ultimo carattere della riga è \"%1\"\n\n", textline.substr( textline.size() - 1, 1 ) ) );
							result = false;
							errori++;
						}
					}
					if ( result )
					{
						conta++;
						_domande->push_back ( *temp );
					}
					delete temp;
					temp = 0;
				}
			}
		}
		_mainStatusbar->pop ( _stsbarItemDiskId );
		if ( conta >= 0 )
		{
			messaggio.append ( Glib::ustring::format ( conta ) );
			if ( conta == 1 )
				messaggio.append ( " domanda" );
			else
				messaggio.append ( " domande" );
			if ( errori > 0 )
			{
				if ( errori == 1 )
					messaggio.append ( ", ho rilevato un errore." );
				else
					messaggio.append ( Glib::ustring::compose ( ", ho rilevato %1 errori.", Glib::ustring::format ( errori ) ) );
				if ( error_log.size() > 0 )
				{
					error_log_textbuffer->set_text (error_log);
					error_log_win->present ();
				}
			}
			else
				messaggio.append ( Glib::ustring ( "." ) );
			_mainStatusbar->push ( messaggio, _stsbarItemDiskId );
		}
		else
			_mainStatusbar->push ( Glib::ustring ( "Nessuna domanda importata." ), _stsbarItemDiskId );
		if ( conta > 0 )
		{
			_shouldSaveDomande = true;
			_saveToolButton->set_sensitive ( true );
			_saveMenuitem->set_sensitive ( true );
		}
	}
	infile.close();
}

bool Controller::
try_get_next_string ( ifstream &infile, Domanda *temp, string &textline, const string &next, size_t *start_pos, Glib::ustring &segmento )
{
	bool result = true;
	bool try_again = true;
	Glib::ustring cache_str ( "" );
	while ( try_again )
	{
		if ( get_next_string (textline, next, start_pos, segmento) )
		{
			if ( cache_str != Glib::ustring ( "" ) )
			{
				cache_str.append ( segmento );
				segmento.assign ( cache_str );
			}
			//temp->set_domanda ( segmento );
			try_again = false;
			result = true;
		}
		else
		{
			cout << "get_next_string fallito!" << endl;
			if ( textline.find ( next[0], *start_pos + 1 ) == string::npos )
			{
				cout << "nessun separatore, tento riga successiva" << endl;
				cache_str.append ( segmento );
				cout << "metto nella cache \"" << segmento.raw() << "\"" << endl;
				if ( getline ( infile, textline, '\n' ) )
					*start_pos = -1;
				else
				{
					cout << "getline fallito!" << endl;
					try_again = false;
					result = false;
				}
			}
			else
			{
				cout << "ho trovato un altro separatore, mi arrendo" << endl;
				try_again = false;
				result = false;
			}
		}
	}
	return result;
}

bool Controller::
get_next_string ( const string &textline, const string &next, size_t *start_pos, Glib::ustring &segmento )
{
	bool result = false;
	size_t next_sep_pos = textline.find ( next, *start_pos + 1 );
	if ( next_sep_pos != string::npos )
	{
		size_t found_size = next_sep_pos - *start_pos - 1;
		segmento.assign ( textline.substr( *start_pos + 1, found_size ) );
		bool valido = segmento.validate();
		if ( !valido )
			segmento.assign ( segmento.substr ( 1 ) );
		*start_pos = next_sep_pos;
		result = true;
	}
	else
	{
		segmento.assign( textline.substr( *start_pos + 1 ) );
		bool valido = segmento.validate();
		if ( !valido )
			segmento.assign ( segmento.substr ( 1 ) );
	}
	return result;
}

void Controller::
populate_edit_window ( const Domanda &quaestio )
{
	_editCodiceEntry->set_text ( quaestio.get_codice() );
	_editArgomentoEntry->set_text ( quaestio.get_argomento () );
	quaestio.get_domanda ( _editDomandaTxtBfr );
	quaestio.get_risposta ( 0, _editRispATxtBfr );
	quaestio.get_risposta ( 1, _editRispBTxtBfr );
	quaestio.get_risposta ( 2, _editRispCTxtBfr );
	quaestio.get_risposta ( 3, _editRispDTxtBfr );
	quaestio.get_appunti ( _editAppuntiTxtBfr );
	_editCorrettaCombobox->set_active ( quaestio.get_corretta () );
}

void Controller::
on_edit_tag_apply ( const Glib::ustring &tagName )
{
	Gtk::TextBuffer::iterator start;
	Gtk::TextBuffer::iterator end;
	if ( _editDomandaTxtView->has_focus () && _editDomandaTxtBfr->get_selection_bounds ( start, end ) )
		_editDomandaTxtBfr->apply_tag_by_name ( tagName, start, end );
	if ( _editRispATxtView->has_focus () && _editRispATxtBfr->get_selection_bounds ( start, end ) )
		_editRispATxtBfr->apply_tag_by_name ( tagName, start, end );
	if ( _editRispBTxtView->has_focus () && _editRispBTxtBfr->get_selection_bounds ( start, end ) )
		_editRispBTxtBfr->apply_tag_by_name ( tagName, start, end );
	if ( _editRispCTxtView->has_focus () && _editRispCTxtBfr->get_selection_bounds ( start, end ))
		_editRispCTxtBfr->apply_tag_by_name ( tagName, start, end );
	if ( _editRispDTxtView->has_focus () && _editRispDTxtBfr->get_selection_bounds ( start, end ))
		_editRispDTxtBfr->apply_tag_by_name ( tagName, start, end );
	if ( _editAppuntiTxtView->has_focus () && _editAppuntiTxtBfr->get_selection_bounds ( start, end ))
		_editAppuntiTxtBfr->apply_tag_by_name ( tagName, start, end );
}

void Controller::
on_edit_erase_tag ( void )
{
	Gtk::TextBuffer::iterator start;
	Gtk::TextBuffer::iterator end;
	if ( _editDomandaTxtView->has_focus () && _editDomandaTxtBfr->get_selection_bounds ( start, end ) )
		_editDomandaTxtBfr->remove_all_tags ( start, end );
	if ( _editRispATxtView->has_focus () && _editRispATxtBfr->get_selection_bounds ( start, end ) )
		_editRispATxtBfr->remove_all_tags ( start, end );
	if ( _editRispBTxtView->has_focus () && _editRispBTxtBfr->get_selection_bounds ( start, end ) )
		_editRispBTxtBfr->remove_all_tags ( start, end );
	if ( _editRispCTxtView->has_focus () && _editRispCTxtBfr->get_selection_bounds ( start, end ) )
		_editRispCTxtBfr->remove_all_tags ( start, end );
	if ( _editRispDTxtView->has_focus () && _editRispDTxtBfr->get_selection_bounds ( start, end ) )
		_editRispDTxtBfr->remove_all_tags ( start, end );
	if ( _editAppuntiTxtView->has_focus () && _editAppuntiTxtBfr->get_selection_bounds ( start, end ) )
		_editAppuntiTxtBfr->remove_all_tags ( start, end );
}

void Controller::
on_edit_conferma_button_clicked ( void )
{
	bool result = true;
	int nrSel = _domandeListSelection->count_selected_rows ();
	Glib::ustring codice = _editCodiceEntry->get_text ();
	Glib::ustring domanda = _editDomandaTxtBfr->get_text ();
	Glib::ustring rispostaA = _editRispATxtBfr->get_text ();
	Glib::ustring rispostaB = _editRispBTxtBfr->get_text ();
	Glib::ustring rispostaC = _editRispCTxtBfr->get_text ();
	Glib::ustring rispostaD = _editRispDTxtBfr->get_text ();
	char corretta = _editCorrettaCombobox->get_active_row_number ();
	if ( codice.raw() != "" && domanda.raw() != "" && rispostaA != "" && rispostaB != "" && rispostaC != "" && rispostaD != "" )
	{
		if ( nrSel == 0 )
		{
			Domanda _quaestio;
			_quaestio.set_codice ( codice );
			_quaestio.set_argomento ( _editArgomentoEntry->get_text () );
			_quaestio.set_domanda ( _editDomandaTxtBfr );
			_quaestio.set_risposta ( _editRispATxtBfr, 0 );
			_quaestio.set_risposta ( _editRispBTxtBfr, 1 );
			_quaestio.set_risposta ( _editRispCTxtBfr, 2 );
			_quaestio.set_risposta ( _editRispDTxtBfr, 3 );
			_quaestio.set_appunti ( _editAppuntiTxtBfr );
			_quaestio.set_corretta ( corretta );
			list<Domanda>::iterator _found = find ( _domande->begin(), _domande->end(), _quaestio );
			if ( _found != _domande->end() )
			{
				Gtk::MessageDialog *_alertDialog = new Gtk::MessageDialog ( *_mainWin, "Una domanda con lo stesso codice è già presente, vuoi sostituirla con questa?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
				int res_id = _alertDialog->run();
				delete _alertDialog;
				if ( res_id == Gtk::RESPONSE_YES )
				{
					_found->set_domanda ( _quaestio.get_domanda() );
					_found->set_argomento ( _quaestio.get_argomento () );
					_found->set_risposta ( _quaestio.get_risposta ( 0 ), 0 );
					_found->set_risposta ( _quaestio.get_risposta ( 1 ), 1 );
					_found->set_risposta ( _quaestio.get_risposta ( 2 ), 2 );
					_found->set_risposta ( _quaestio.get_risposta ( 3 ), 3 );
					_found->set_appunti ( _quaestio.get_appunti () );
					_found->set_corretta ( _quaestio.get_corretta () );
				}
			}
			else
			{
				_domande->push_back ( _quaestio );
				on_items_tree_selection_changed ();
			}
		}
		else
		{
			vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ();
			Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
			vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
			vector<Gtk::TreePath>::const_iterator _end = _selected.end ();
			list<Domanda>::iterator _iterDomande;
			list<Domanda>::iterator _endDomande = _domande->end();
			while ( _iter != _end )
			{
				Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
				_iterDomande = get_domanda_iterator ( *_iterView );
				if ( _iterDomande != _endDomande )
				{
					if ( nrSel == 1 )
					{
						_iterDomande->set_codice ( codice );
						_iterDomande->set_argomento ( _editArgomentoEntry->get_text () );
						_iterDomande->set_domanda ( _editDomandaTxtBfr );
						_iterDomande->set_risposta ( _editRispATxtBfr, 0 );
						_iterDomande->set_risposta ( _editRispBTxtBfr, 1 );
						_iterDomande->set_risposta ( _editRispCTxtBfr, 2 );
						_iterDomande->set_risposta ( _editRispDTxtBfr, 3 );
						_iterDomande->set_appunti ( _editAppuntiTxtBfr );
						_iterDomande->set_corretta ( corretta );
					}
					
				}
				else
					cerr << "Errore: non ho trovato la Domanda da modificare!" << endl;
				_iter++;
			}
		}
	}
	else
	{
		Gtk::MessageDialog *_alertDialog = new Gtk::MessageDialog ( *_editWin, "Nessun campo può essere lasciato vuoto!", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
		int res_id = _alertDialog->run();
		delete _alertDialog;
		if ( res_id == Gtk::RESPONSE_OK )
			result = false;
	}
	if ( result )
	{
		_shouldSaveDomande = true;
		_saveToolButton->set_sensitive ( true );
		_saveMenuitem->set_sensitive ( true );
		load_domande_in_tree_view ();
		_editWin->hide ();
	}
}

void Controller::
on_previous_info_item_action ( void )
{
	int nrSel = _domandeListSelection->count_selected_rows ();
	if ( nrSel > 0 )
	{
		Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
		vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ( _domandeListModel );
		vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
		Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
		Gtk::TreeModel::iterator _iterBegin = _domandeListStore->children().begin();
		if ( _iterView != _iterBegin )
		{
			_domandeListSelection->unselect ( _iterView );
			_iterView--;
			_domandeListSelection->select ( _iterView );
			on_info_action_clicked ();
		}
	}
}

void Controller::
on_next_info_item_action ( void )
{
	int nrSel = _domandeListSelection->count_selected_rows ();
	if ( nrSel > 0 )
	{
		Glib::RefPtr<Gtk::TreeModel> _domandeListModel = _domandeListView->get_model ();
		vector<Gtk::TreePath> _selected = _domandeListSelection->get_selected_rows ( _domandeListModel );
		vector<Gtk::TreePath>::const_iterator _iter = _selected.begin ();
		Gtk::TreeModel::iterator _iterView = _domandeListModel->get_iter ( *_iter );
		Gtk::TreeModel::iterator _iterEnd = _domandeListStore->children().end();
		_iterEnd--;
		if ( _iterView != _iterEnd )
		{
			_domandeListSelection->unselect ( _iterView );
			_iterView++;
			_domandeListSelection->select ( _iterView );
			on_info_action_clicked ();
		}
	}
}

void Controller::
on_search_conferma_button_clicked ( void )
{
	if ( _searchCodiceEntry->get_text () != "" || _searchDomandaEntry->get_text () != "" || _searchArgomentoEntry->get_text () != "" )
	{
		if ( !_searchToolButton->get_active () )
			_searchToolButton->set_active ( true );
	}
	else
	{
		if ( _searchToolButton->get_active () )
			_searchToolButton->set_active ( false );
	}
	load_domande_in_tree_view ();
	_searchWin->hide ();
}

void Controller::
on_search_default_button_clicked ( void )
{
	_searchCodiceEntry->set_text ( "" );
	_searchDomandaEntry->set_text ( "" );
	_searchArgomentoEntry->set_text ( "" );
}

void Controller::
on_test_opt_inizia_button_clicked ( void )
{
	list<Domanda> *_selezioneDomande = new list<Domanda>;
	prepara_selezione_domande ( _selezioneDomande );
	_testCtrl = new TestSceltaMultDomande ( _builder, _selezioneDomande );
	_testQuaestioEditConnection = _testCtrl->signal_domanda_edit ().connect (sigc::mem_fun (this, &Controller::on_signal_domanda_edit) );
	_testQuaestioChangedConnection = _testCtrl->signal_domande_changed ().connect (sigc::mem_fun (this, &Controller::on_signal_domande_changed) );
	_testWinClosedConnection = _testCtrl->signal_window_closed ().connect (sigc::mem_fun (this, &Controller::on_test_win_closed) );
	_testOptWin->hide ();
	_testCtrl->run_test ();
}

void Controller::
prepara_selezione_domande ( list<Domanda> *_selezionate )
{
	if ( _selezionate )
	{
		Glib::ustring codStr = _testOptCodiceEntry->get_text();
		bool codValido = ( codStr != Glib::ustring ( "" ) );
		Glib::ustring argStr = _testOptArgomentoEntry->get_text ();
		bool argValido = ( argStr != Glib::ustring ( "" ) );
		double percent = _testOptPercentScale->get_value();
		list<Domanda>::iterator iterList = _domande->begin();
		list<Domanda>::iterator endList = _domande->end();
		while ( iterList != endList )
		{
			bool _match = true;
			if ( codValido )
			{
				if ( iterList->get_codice().find( codStr ) == -1 )
					_match = false;
			}
			if ( _match )
			{
				if ( argValido )
				{
					if ( iterList->get_argomento().find( argStr ) == -1 )
						_match = false;
				}
				if ( _match )
				{
					if ( percent < 100 )
					{
						if ( iterList->get_risposte () > 0 && ( ( iterList->get_corrette () * 100 ) / iterList->get_risposte () ) > percent )
							_match = false;
					}
					if ( _match )
						_selezionate->push_back ( *iterList );
				}
			}
			iterList++;
		}
	}
}

void Controller::
on_signal_domande_changed ( const Domanda &quaestio )
{
	list<Domanda>::iterator _iter = find ( _domande->begin(), _domande->end(), quaestio );
	if ( _iter != _domande->end() )
	{
		_iter->set_risposte ( quaestio.get_risposte () );
		_iter->set_corrette ( quaestio.get_corrette () );
		_iter->set_ultima ( quaestio.get_ultima () );
		_iter->set_tempo_totale ( quaestio.get_tempo_totale () );
		_iter->set_ultimo_tempo ( quaestio.get_ultimo_tempo () );
		_shouldSaveDomande = true;
		_saveToolButton->set_sensitive ( true );
		_saveMenuitem->set_sensitive ( true );
	}
}

void Controller::
on_signal_domanda_edit ( const Domanda &quaestio )
{
	populate_edit_window ( quaestio );
	_editWin->present ();
}

void Controller::
on_test_win_closed ( void )
{
	_testQuaestioEditConnection.disconnect ();
	_testQuaestioChangedConnection.disconnect ();
	_testWinClosedConnection.disconnect ();
	delete _testCtrl;
	_testCtrl = 0;
	_testOptWin->present ();
}

void Controller::
on_signal_domanda_loaded ( const Domanda &quaestio )
{
	int res_id = 0;
	list<Domanda>::iterator _found = find ( _domande->begin(), _domande->end(), quaestio );
	if ( _found != _domande->end() )
	{
		Glib::ustring messaggio = Glib::ustring ( "La domanda \"" ) + quaestio.get_domanda() + Glib::ustring ( "\" è già presente nel database, vuoi sostituirla con quella importata?" );
		Gtk::MessageDialog *_alertDialog = new Gtk::MessageDialog ( *_mainWin, messaggio, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
		res_id = _alertDialog->run();
		delete _alertDialog;
		if ( res_id == Gtk::RESPONSE_YES )
			_domande->erase ( _found );
	}
	if ( res_id != Gtk::RESPONSE_NO )
	{
		_domande->push_back ( quaestio );
		_domandeCaricate++;
	}
}

void Controller::
on_signal_import_end ( void )
{
	Glib::ustring messaggio = "Caricato: ";
	if ( _domandeCaricate > 0 )
	{
		load_domande_in_tree_view ();
		messaggio.append ( Glib::ustring::compose ( "%1 domande", Glib::ustring::format ( _domandeCaricate ) ) );
	}
	_mainStatusbar->pop ( _stsbarItemDiskId );
	_mainStatusbar->push ( messaggio, _stsbarItemDiskId );
	
	if ( _startingApp == STATUS_RUNNING )
	{
		if ( _domandeCaricate > 0 )
			_shouldSaveDomande = true;
	}
	else
		_startingApp = STATUS_RUNNING;
}
